package cn.zzf.algs.note.base.collection.v1;

import edu.princeton.cs.algs4.StdOut;

import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;

/**
 * @author GaoFeng
 * @date 2019/11/21 21:15
 */
public class ResizingArrayQueue<T> implements Iterable<T>, Queue<T> {

    private int head;
    private int tail;
    private T[] elements;
    private int size;

    @SuppressWarnings("unchecked")
    public ResizingArrayQueue() {
        this.head = 0;
        this.tail = 0;
        this.elements = (T[]) new Object[1];
    }

    @Override
    public void enqueue(T element) {

        if (tail == elements.length) {
            this.changeCapacity(this.size * 2);
        }

        this.elements[tail++] = element;
        size++;
    }

    @SuppressWarnings("unchecked")
    private void changeCapacity(int capacity) {

        StdOut.println("change capacity, " + this.size + " -> " + capacity);
        T[] newElements = (T[]) new Object[capacity];

        int index = 0;
        for (int i = head; i < tail; i++) {
            newElements[index++] = elements[i];
        }

        this.elements = newElements;
        this.head = 0;
        this.tail = index;

    }

    @Override
    public T dequeue() {

        if(size == 0) {
            return null;
        }

        if (size == elements.length / 4) {
            this.changeCapacity(elements.length / 2);
        }

        T element = elements[head];

        elements[head++] = null;
        size--;

        return element;
    }

    @Override
    public boolean isEmpty() {
        return this.size() > 0;
    }

    @Override
    public int size() {
        return this.size;
    }


    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {

            private int currentIndex = head;

            @Override
            public boolean hasNext() {
                return currentIndex < tail;
            }

            @Override
            public T next() {

                if (currentIndex < tail) {
                    return elements[currentIndex++];
                }

                return null;

            }
        };
    }

    @Override
    public void forEach(Consumer<? super T> action) {

    }

    @Override
    public Spliterator<T> spliterator() {
        return null;
    }
}
